package com.wsjc.manager.service.rpc.map.impl;

import java.text.NumberFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.wsjc.common.core.constants.CommonConst;
import com.wsjc.common.core.enums.MunicipalEnum;
import com.wsjc.common.core.utils.StringUtil;
import com.wsjc.common.redis.RedisUtils;
import com.wsjc.manager.entity.WjHospital;
import com.wsjc.manager.entity.vo.map.MapResultVo;
import com.wsjc.manager.entity.vo.map.RegionVo;
import com.wsjc.manager.service.routine.hospital.WjHospitalService;
import com.wsjc.manager.service.routine.region.WjRegionService;
import com.wsjc.manager.service.rpc.map.WjMapService;
import com.wsjc.manager.service.rpc.map.utils.BuildCacheKeys;

import redis.clients.jedis.Jedis;

@Service("wjMapService")
public class WjMapServiceImpl implements WjMapService {

	private static Logger logger = LoggerFactory.getLogger(WjMapServiceImpl.class);
	
	@Autowired
	public RedisUtils redisUtils ;
	
	@Autowired
	public WjRegionService wjRegionService ;
	
	@Autowired
	public WjHospitalService wjHospitalService ;
	
	
	/**
	 * 获取地图数据
	 */
	@Override
	public MapResultVo loadMap(String scope, String dataType) throws Exception{
		
		Jedis jedis = redisUtils.instanceJedisFactory("agent");
		/** 先统计出 scope 下医院 合格，不合格，总数，其他 个数，以及合格率。**/
		String showKey = BuildCacheKeys.buildShowKey(dataType, scope) ;
		String jsonResultVo = jedis.get(showKey) ;
		MapResultVo mapResultVo =  JSON.parseObject(jsonResultVo, MapResultVo.class);
		redisUtils.releaseResource(jedis);
		return mapResultVo;
	}
	


	/**
	 * 初始化地图
	 * 医院都是无数据
	 * detectionResult 0
	 */
	@Override
	public void initMap(String detectionResult, String hospitalId, String dataType, String areaId) {
		
        Map<String, String> mapKeys = BuildCacheKeys.buildDetectionResultKeys(dataType, areaId) ;
		
		Jedis jedis = redisUtils.instanceJedisFactory("agent");
		try {
			for(Map.Entry<String, String> key : mapKeys.entrySet()){
				/**效验key 是否存在，不存在，则创建, hash 结构, 初始值 0 代表该医院无数据 **/
				boolean falg = redisUtils.exists(jedis, key) ;
				if(!falg){
					redisUtils.addHash(jedis, key.getValue(), hospitalId, detectionResult);
				}
			}
			
			// 更新缓存医院展示信息
	        flushHospitalShowMapData(jedis, hospitalId, detectionResult, "", "", dataType);
			
			
		} catch (Exception e) {
			logger.error("INIT-MAP|error|fand exception :", e);
		}finally {
			redisUtils.releaseResource(jedis);
		}
		
	}
	
	
	/**
	 * 刷新地图
	 * 更新该数据对应 全国，省，市，区 的 地图缓存。
	 * @param detectionResult 监测数据结果 1：合格，2：不合格，3：数据过期，0：无数据。
	 * @author 93733
	 */
	@Override
	public void flushMap(String detectionResult, String hospitalId, String dataType, String areaId, String ossDir,
			String detectionTime) {
		
		String areaKey = BuildCacheKeys.buildDetectionResultKey(dataType, areaId) ;
		
		Jedis jedis = redisUtils.instanceJedisFactory("agent");
		
		/**效验 该医院缓存中数据是否和最新数据不一致，不一致则进行更新。**/
		String result = redisUtils.getHash(jedis, areaKey, hospitalId);
		if(StringUtil.isNotNull(result) && result.equals(detectionResult)){
			return; 
		}
		logger.info("FLUSH-MAP|info|start flush map...");
		
		/** 更新缓存中该医院最新数据结果 **/
		Map<String, String> dataKeys = BuildCacheKeys.buildDetectionResultKeys(dataType, areaId) ;
        for(Map.Entry<String, String> dataKey : dataKeys.entrySet()){
        	redisUtils.addHash(jedis, dataKey.getValue(), hospitalId, detectionResult);
		}
        
        // 更新缓存医院展示信息
        flushHospitalShowMapData(jedis, hospitalId, detectionResult, ossDir, detectionTime, dataType);
        
        /** 处理对应 全国、省、市、区, 医院 地图颜色 **/
        handleMapShowData(jedis, detectionResult, hospitalId, dataType, areaId, ossDir, detectionTime);
			
		redisUtils.releaseResource(jedis);
	}

	/**
	 * 处理更新 全国 ，省，市，区，医院展示内容
	 * @param jedis
	 * @param detectionResult
	 * @param hospitalId
	 * @param dataType
	 * @param areaId
	 * @param ossDir
	 * @param detectionTime
	 */
	private void handleMapShowData(Jedis jedis, String detectionResult, String hospitalId, String dataType, String areaId,
			String ossDir, String detectionTime) {
		
		List<RegionVo> provinces = wjRegionService.queryAllProvinces();
    	String provinceId = areaId.substring(0, 2)+"0000";
    	MunicipalEnum municipalEnum = MunicipalEnum.getEnum("P"+provinceId);
    	List<RegionVo> cities = null ;
    	List<RegionVo> areas ;
    	String cityId = null ;
    	if(null != municipalEnum){
    		areas = wjRegionService.queryAllAreasByCityId(provinceId, null);
    	}else{
    		cities = wjRegionService.queryAllCitysByProvinceId(provinceId);
    		cityId = areaId.substring(0, 4)+"00";
            areas = wjRegionService.queryAllAreasByCityId(null, cityId);
    	}
        
        /** 更新展示数据 **/
		Map<String, String> showKeys = BuildCacheKeys.buildShowKeys(dataType, areaId) ;
		for(Map.Entry<String, String> showKey : showKeys.entrySet()){
			
			String key = showKey.getKey() ;
			String value = showKey.getValue();
			MapResultVo resultVo = new MapResultVo();
			
			if(key.equals("countryKey")){
				resultVo.setLowerRegionVo(provinces);
				/** 全国级处理 **/
				buildScopeShowData(jedis, resultVo, dataType, "000000");
	            // 全国下级数据计算
	            for(RegionVo province : provinces){
	            	/** 构建 scope 下级区域 show map **/
	            	buildLowerShowMapColor(dataType, resultVo, jedis, province);
	            }
			}else if(key.equals("provinceKey")){
				if(null != municipalEnum){
					resultVo.setLowerRegionVo(areas);
					/** 省级处理 **/
					buildScopeShowData(jedis, resultVo, dataType, provinceId);
		            // 全国下级数据计算
		            for(RegionVo area: areas){
		            	/** 构建 scope 下级区域 show map **/
		            	buildLowerShowMapColor(dataType, resultVo, jedis, area);
		            }
		    	}else{
		    		resultVo.setLowerRegionVo(cities);
					/** 省级处理 **/
					buildScopeShowData(jedis, resultVo, dataType, provinceId);
		            // 全国下级数据计算
		            for(RegionVo city: cities){
		            	/** 构建 scope 下级区域 show map **/
		            	buildLowerShowMapColor(dataType, resultVo, jedis, city);
		            }
		    	}
			}else if(key.equals("cityKey")){
				resultVo.setLowerRegionVo(areas);
				/** 市级处理 **/
				buildScopeShowData(jedis, resultVo, dataType, cityId);
	            // 全国下级数据计算
	            for(RegionVo area: areas){
	            	/** 构建 scope 下级区域 show map **/
	            	buildLowerShowMapColor(dataType, resultVo, jedis, area);
	            }
			}else if(key.equals("areaKey")){
				/** 区级处理 **/
				buildScopeShowData(jedis, resultVo, dataType, areaId);
	            // 区下医院数据计算
	            String detectionResultKey = BuildCacheKeys.buildDetectionResultKey(dataType, areaId) ;
	            Set<String> keys = redisUtils.getAllKeys(jedis, detectionResultKey);
	            
	            /** 重新构建该区所有医院展示信息 **/
	            for(String hosId: keys){
            		buildLowerShowMapColor(dataType, resultVo, jedis, hosId);
	            }
			}
			
			// 存入redis String 类型中。
            String scopeJsonData = JSONObject.toJSONString(resultVo);
            jedis.set(value, scopeJsonData);
			
		}
		
	}



	/**
	 * 构建区域展示数据
	 * @param jedis
	 * @param resultVo
	 * @param dataType
	 * @param scope
	 */
	public void buildScopeShowData(Jedis jedis, MapResultVo resultVo, String dataType, String scope){
		
		/** 先统计出 scope 下医院 合格，不合格，总数，其他 个数，以及合格率。**/
		String scopekey = BuildCacheKeys.buildDetectionResultKey(dataType, scope) ;
		List<String> detectionResults = redisUtils.getAllValues(jedis, scopekey);
		int total = detectionResults.size();
		resultVo.setHosTotal(total);
		
		long noDataTotal = detectionResults.stream().filter(detectionResult -> detectionResult.equals("0")).count();
		resultVo.setNoDataHosTotal(noDataTotal);
		
		long passDataTotal = detectionResults.stream().filter(detectionResult -> detectionResult.equals("1")).count();
		resultVo.setPassHosTotal(passDataTotal);
		
		long nonPassDataTotal = detectionResults.stream().filter(detectionResult -> detectionResult.equals("2")).count();
		resultVo.setNonHosPassTotal(nonPassDataTotal);
         			
		long expireDataTotal = detectionResults.stream().filter(detectionResult -> detectionResult.equals("3")).count();
		resultVo.setExpireDataHosTotal(expireDataTotal);
		
		String bfb = getBFB(passDataTotal, total);
		resultVo.setRegionPercent(bfb);
		
	}
	
	
	/**
	 * 构建scope 下级区域颜色
	 * @param dataType
	 * @param lowerScopes 下级区域：（1）省市区Id
	 * @param resultVo 内层map 中id 可能是 regionId 也可能是 hospitalId...取决于 showType
	 * @param showType 展示类别，hospital 展示医院，region展示区域
	 */
	private void buildLowerShowMapColor(String dataType, MapResultVo resultVo, Jedis jedis, RegionVo regionVo) {

		/** 获取该区域百分比 **/
		String lowerScopeKey = BuildCacheKeys.buildDetectionResultKey(dataType, regionVo.getId());
		List<String> detectionResults = redisUtils.getAllValues(jedis, lowerScopeKey);
		int total = detectionResults.size();
		long noDataTotal = detectionResults.stream().filter(detectionResult -> detectionResult.equals("0")).count();
		if (noDataTotal == total) {
			// 无数据
			regionVo.setColor(CommonConst.COLOR_TYPE_GRAY);
			return ;
		}
		// 有数据往下执行
		long passDataTotal = detectionResults.stream().filter(detectionResult -> detectionResult.equals("1")).count();
		String bfb = getBFB(passDataTotal, total);
		/** 区域百分比得到对应的color **/
		setRegionColorToMapResultVo(bfb, regionVo);

	}
	
	
	/**
	 * 构建区 下级 医院展示数据
	 * @param dataType
	 * @param jedis
	 * @param resultVo 内层map 中id 可能是 regionId 也可能是 hospitalId...取决于 showType
	 * @param hospitalId
	 */
	@SuppressWarnings("unchecked")
	private void buildLowerShowMapColor(String dataType, MapResultVo resultVo, Jedis jedis, String hospitalId) {

		// 获取该医院缓存的展示数据
        String key = BuildCacheKeys.buildHospitalShowDataKey(dataType, hospitalId);
        String value = jedis.get(key);
        
		/** 将下级区域Id 封装到响应map 中 **/
		Map<String, String> lowerScopeResult = JSON.parseObject(value, Map.class);

		// 将下级区域最后的结果封装到 resultVo 中。
		resultVo.addLowerScopeShow(lowerScopeResult);

	}
	
	
	/**
	 * 更新 地图 医院展示信息
	 * @param hospitalId
	 * @param detectionResult
	 * @param ossDir
	 * @param detectionTime
	 * @param dataType
	 */
	@SuppressWarnings("unchecked")
	private void flushHospitalShowMapData(Jedis jedis, String hospitalId, String detectionResult, String ossDir, String detectionTime
			, String dataType) {

		Map<String, String> hospitalShowData = Maps.newHashMap();
		
		// 验证是否已有缓存
        String key = BuildCacheKeys.buildHospitalShowDataKey(dataType, hospitalId);
        boolean falg = jedis.exists(key);
        if(falg){
        	logger.info("map-flush|the hospital info at redis exists..so flush : detectionResult, ossDir, detectionTime");
        	String str = jedis.get(key);
        	Map<String, String> info = JSON.parseObject(str, Map.class);
        	info.put("detectionResult", detectionResult) ;
        	info.put("ossDir", ossDir) ;
        	info.put("detectionTime", detectionTime) ;
        }else{
        	logger.info("map-flush|the hospital info at redis no exists..so flush all..");
        	/** 封装医院所有地图展示信息 **/
    		hospitalShowData.put("id", hospitalId) ;
    		hospitalShowData.put("detectionResult", detectionResult) ;
    		hospitalShowData.put("ossDir", ossDir) ;
        	hospitalShowData.put("detectionTime", detectionTime) ;
        	
        	// 获取医院信息
        	WjHospital wjHospital = wjHospitalService.queryWjHospitalById(hospitalId);
        	hospitalShowData.put("hospitalName", wjHospital.getName()) ;
        	hospitalShowData.put("address", wjHospital.getAddress()) ;
        	hospitalShowData.put("baiduGpsX", wjHospital.getBaiduGpsX()) ;
        	hospitalShowData.put("baiduGpsY", wjHospital.getBaiduGpsY()) ;
        	hospitalShowData.put("gaodeGpsX", wjHospital.getGaodeGpsX()) ;
        	hospitalShowData.put("gaodeGpsY", wjHospital.getGaodeGpsY()) ;
        }
    	// 存入redis String 类型中。
        String str = JSONObject.toJSONString(hospitalShowData);
        jedis.set(key, str);
        
	}
	


	/**
     * 设置区域 颜色
     * @param bfb
     * @param lowerScopeResult
     */
	private void setRegionColorToMapResultVo(String bfb, RegionVo regionVo) {
		// 根据合格率 判断颜色  
		Double result = Double.parseDouble( bfb ) ;
        int value = (int) (result * 100) ;
        String color = "" ;
        if(value < 20 ){
        	color = CommonConst.COLOR_TYPE_RED ;         // 红色
        }else if(value >= 20 && value < 40 ){
        	color = CommonConst.COLOR_TYPE_ORANGE ;      // 橙色
        }else if(value >= 40 && value < 60){
        	color = CommonConst.COLOR_TYPE_YELLOW ;      // 黄色
        }else if(value >= 60 && value < 80){
        	color = CommonConst.COLOR_TYPE_GREEN ;       // 浅绿色
        }else if(value >= 80 && value <= 100){
        	color = CommonConst.COLOR_TYPE_DARK_GREEN ;  // 深绿色
        }else {
        }
        /** 将下级区域color 封装到响应map 中 **/
        regionVo.setColor(color);
		
	}
	
	/** 获取百分比 **/
	public static String getBFB(double passDataTotal, double total){
		NumberFormat nbf=NumberFormat.getInstance(); 
		nbf.setMinimumFractionDigits(2); 
		String bfb = nbf.format(passDataTotal/total);
		return bfb;
	}


	
	


}
